using Godot;
using System;
using System.Collections.Generic;
using System.Linq;

public partial class NCharacter : CharacterBody2D
{
	[Export] public CCharacterData mData;

	AnimatedSprite2D mAni;
	CollisionShape2D mShape;
	NTopBar mTopBar;
	Curve mUpgradeCurve;
	AnimationPlayer mAniPlayer;
	List<CLevelExp> mLevelExp = new List<CLevelExp>();
	GpuParticles2D mUpgradeEffect;
	public CollisionShape2D Shape2D
	{ get { return mShape; } }
	void _initLevelExp()
	{
		for (int i = mData.mMinLevel; i <= mData.mMaxLevel; i++)
		{
			mLevelExp.Add(new CLevelExp(i, getExpWithLevel(i)));
		}
		mLevelExp = mLevelExp.OrderBy(i => i.mExp).ToList();
	}
	void _deadAniEnd()
	{
		if (mData.mState is CDeadState ds)
		{
			ds.mDeadAniEnd = true;
		}
	}
	public void relive(float life = 0)
	{
		mData.mLife = life == 0 ? mData.MaxLife : life;
		mAniPlayer.Play("RESET");
		Shape2D.Disabled = false;
		mData.mState = new CIdleState();
	}
	void debug()
	{
		foreach (var v in mLevelExp)
		{
			GD.Print("经验：", v.mExp, "-- 等级：", v.mLevel);
		}
	}
	public AnimationPlayer AniPlayer
	{
		get
		{
			return mAniPlayer;
		}
	}
	public NTopBar TopBar
	{
		get { return mTopBar; }
	}
	public int getExpWithLevel(int level)
	{
		float level01 = (float)(level - mData.mMinLevel) / (float)(mData.mMaxLevel - mData.mMinLevel);
		return (int)(1000 * mUpgradeCurve.SampleBaked(level01));
	}
	public bool IsDead
	{
		get { return mData.mLife <= 0; }
	}
	public void addExp(int exp)
	{
		mData.mExp += exp;
		int tarLevel = mData.mMaxLevel;
		foreach (var v in mLevelExp)
		{
			if (mData.mExp < v.mExp)
			{
				tarLevel = v.mLevel - 1;
				break;
			}
		}
		if (tarLevel > mData.mLevel)
		{
			mData.mLevel = tarLevel;
			_upgrade();
		}
		GD.Print(Name, ":", mData.mExp, "-- 等级：", mData.mLevel);
	}
	void _upgrade()
	{
		mData.mLife = mData.MaxLife;
		mUpgradeEffect.Emitting = true;
	}
	public override void _Ready()
	{
		mUpgradeEffect = GetNode<GpuParticles2D>("%GPUParticles2D");
		mAniPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
		mUpgradeCurve = CHelp.loadRes<Curve>("res://scene/cha/upgrade.tres");
		mTopBar = GetNode<NTopBar>("%NTopBar");
		mAni = GetNode<AnimatedSprite2D>("AnimatedSprite2D");
		mShape = GetNode<CollisionShape2D>("CollisionShape2D");

		CHelp.addToGroup(this, mData.mChaType.ToString());

		if (mData == null)
			mData = new CCharacterData();

		mData = mData.copy();

		_loadSkills();
		_initLevelExp();
	}

	void _loadSkills()
	{
		string[] skillsPath = new string[] {
			"res://scene/skill/data/物理攻击.tres"
			,"res://scene/skill/data/远程攻击.tres"
			,"res://scene/skill/data/弓箭攻击.tres" };

		mData.mSkills.Clear();
		foreach (var v in skillsPath)
		{
			mData.mSkills.Add(CHelp.loadRes<CSkill>(v).copy());
		}
	}

	public void beAttack(NCharacter emeny)
	{
		if (mData.mState is CIdleState)
		{
			mData.mSkillTarget.mID = mData.mDefauldID;
			mData.mSkillTarget.mTargetPath = CHelp.getNearestEnemy(this, 1000).GetPath().ToString();
			mData.mState = new CPreSkillState();
		}
	}

	public AnimatedSprite2D Ani
	{
		get { return mAni; }
	}

	public float ColShapeDis
	{
		get
		{
			if (mShape.Shape is CircleShape2D cs)
			{
				return cs.Radius;
			}
			return 0;
		}
	}

	public CSkill CurSkill
	{
		get
		{
			return getSkill(mData.mSkillTarget.mID);
		}
	}

	// Called every frame. 'delta' is the elapsed time since the previous frame.
	public override void _Process(double delta)
	{
		_checkDead();
		_updateTopBar();
		mData.mState.run(this, delta);
	}

	void _checkDead()
	{
		if (IsDead && mData.mState is not CDeadState)
		{
			_drop();
			mData.mState = new CDeadState();
		}
	}

	void _drop()
	{
		if (mData.mChaType == CHA_TYPE.FRIEND)
			return;

		int exp1 = getExpWithLevel(mData.mLevel);
		int exp2 = getExpWithLevel(mData.mLevel + 1);
		int dropExp = (exp2 - exp1) / mData.mLevel;
		if (dropExp <= 0)
			dropExp = 1;

		CHelp.getTeamCha(this).addExp(dropExp);
	}

	void _updateTopBar()
	{
		if (mData.mChaType == CHA_TYPE.FRIEND)
			mTopBar.Visible = true;
		if (mData.mChaType == CHA_TYPE.ENEMY)
		{
			mTopBar.Visible = Rect.HasPoint(GetGlobalMousePosition());
		}
		mTopBar.setPercent(mData.mLife / mData.MaxLife);
		mTopBar.setLevel(mData.mLevel);
	}

	public Rect2 Rect
	{
		get
		{
			if (mShape.Shape is CircleShape2D cs)
			{
				return new Rect2(GlobalPosition.X - cs.Radius, GlobalPosition.Y - cs.Radius, 2 * cs.Radius, 2 * cs.Radius);
			}
			return new Rect2();
		}
	}
	public override void _UnhandledInput(InputEvent @event)
	{
		if (@event is InputEventMouseButton mb)
		{
			if (mb.Pressed && mb.ButtonIndex == MouseButton.Right)
			{
				if (mData.mChaType == CHA_TYPE.FRIEND)
				{
					mData.mMoveTarget = GetGlobalMousePosition();
					mData.mState = new CMoveState();
				}
			}
		}
	}

	public CSkill getSkill(SKILL_ID id)
	{
		foreach (var v in mData.mSkills)
		{
			if (v.mID == id)
			{
				return v;
			}
		}
		return null;
	}

	public void play(ANI_TYPE at)
	{
		_play(at, mData.mDir);
	}
	void _play(ANI_TYPE at, DIR d)
	{
		string aniName = string.Format("{0}_{1}", at.ToString().ToLower(), d.ToString().ToLower());

		mAni.Play(aniName);
	}
	public string aniName(ANI_TYPE at)
	{
		return string.Format("{0}_{1}", at.ToString().ToLower(), mData.mDir.ToString().ToLower());

	}
}
